import java.util.Vector;

public class Factory extends Thread {

	public static long time = Scarecrow_Factory.time;
	public final int OPERATION_TIME = 20000;
	protected static final int PRODUCTION_TIME_MIN = 2000;
	protected static final int PRODUCTION_TIME_MAX = 5000;
	private int sCrowCount = 0;
	private int totalOfBrooms = 4;
	private int totalOfHeads = 0;
	private int totalOfTorsos = 0;
	private int totalOfHands = 0;
	private int totalOfLegs = 0;
	private int noOfLeastStockedPart = 0;
	static Vector<Truck> truckQue = new Vector<Truck>();
	Manufacturer[] ManufacturerByNeed = new Manufacturer[5]; 
	
	public Factory (int id) {
		setName("Factory-" + id);
	}

	public void msg(String m) {
		System.out.println("["+(System.currentTimeMillis()-time)+"] "+getName()+": "+m);
	}
	
	public void run(){
		msg("Factory Thread has Started Running");
		
		int maxSCrowsPossible;
		
		while ((System.currentTimeMillis()-time) <= OPERATION_TIME){

			if((System.currentTimeMillis()-time) >= (4*OPERATION_TIME/5)){
				Manufacturer.setFactoryAboutToStopOperation(true);
				ManufacturerByNeed = Scarecrow_Factory.sortManufacturers (totalOfBrooms, totalOfHeads, totalOfTorsos, totalOfHands, totalOfLegs);				
				msg("Time to notify Manufacturers");
				msg("1st Most Needed part-->"+ManufacturerByNeed[0]);
				msg("2nd Most Needed part-->"+ManufacturerByNeed[1]);
				msg("3rd Most Needed part-->"+ManufacturerByNeed[2]);
				msg("4th Most Needed part-->"+ManufacturerByNeed[3]);
				msg("5th Most Needed part-->"+ManufacturerByNeed[4]);
				Manufacturer.factoryIsAboutToStopOperation (ManufacturerByNeed);
			}
			
			if (!truckQue.isEmpty()){
				Truck frontTruck = truckQue.remove(0);
				msg("" + frontTruck);
				if (!acceptPart(frontTruck)){
					msg("Part: "+frontTruck.partType+" Not Accepted; Truck #"+frontTruck.truckId+" sent to End of line");
					frontTruck.deliveryAttempts++;
					Truck.yield();
					truckQue.addElement(frontTruck);
				}
				
				maxSCrowsPossible = noOfLeastStockedPart;
				if (maxSCrowsPossible >= 1)
					assembleSCrow();
			} else
				try {
					Factory.sleep(2100);
				} catch (InterruptedException e) {
				}
		}
		
		msg("*************************************");
		msg("FINAL COUNT OF SCARECROWS AND STOCK AFTER FACTORY CLOSING");
		msg(currentStock());
		msg("TOTAL SCARECROWS ASSEMBLED AFTER CLOSING= "+sCrowCount);
		msg("*************************************");
	}

	public synchronized boolean acceptPart( Truck truck ) {
		
		boolean isSurplus = false;
		String partType = truck.getPartType();

		isSurplus = isSurplus(partType);

		if (truck.is2ndTry()){
			if (isSurplus)
				truck.partIsSurplus = true;
			msg("Stock BEFORE accepting Part:");
			msg(currentStock());
			updateInventory(partType);
			msg(partType + " Accepted by factory on 2ND Try from Truck #"+truck.truckId);
			msg("Stock AFTER accepting Part:");
			msg(currentStock());
			msg("TOTAL SCARECROWS ASSEMBLED = "+sCrowCount);

			Scarecrow_Factory.sendTruckBack(truck);
			return true;
		}
		
		if (isSurplus) {
			msg("Part Type " + partType + " is in Surplus");
			return false;
		}

		msg("Stock BEFORE accepting Part:");
		msg(currentStock());
		updateInventory(partType);
		msg(partType + " Accepted by factory on 1ST Try");
		msg("Stock AFTER accepting Part:");
		msg(currentStock());
		msg("TOTAL SCARECROWS ASSEMBLED = "+sCrowCount);

		Scarecrow_Factory.sendTruckBack(truck);
		return true;
	}
	
	private String currentStock(){
		return("Brooms="+totalOfBrooms+"; Heads="+totalOfHeads+"; Torsos="+totalOfTorsos+"; Hands="+totalOfHands+"; Legs="+totalOfLegs);
	}
	
	private boolean isSurplus(String partType){
		int canBeUsedOfType = noOfLeastStockedPart; 		
		
		if (partType == "BROOM" && ((totalOfBrooms-canBeUsedOfType)>2))
			return true;
		else if (partType == "HEAD" && ((totalOfHeads-canBeUsedOfType)>2))
			return true;
		else if (partType == "TORSO" && ((totalOfTorsos-canBeUsedOfType)>2))
			return true;
		else if (partType == "HAND" && (((totalOfHands/2)-canBeUsedOfType)>2))
			return true;
		else if (partType == "LEG" && (((totalOfLegs/2)-canBeUsedOfType)>2))
			return true;
		else return false;

	}
	
	private void updateInventory(String partType){
		if (partType == "BROOM")
			totalOfBrooms++;
		else if (partType == "HEAD")
			totalOfHeads++;
		else if (partType == "TORSO")
			totalOfTorsos++;
		else if (partType == "HAND")
			totalOfHands++;
		else if (partType == "LEG")
			totalOfLegs++;
		updateMinOfStock();
	}
	
	private void updateMinOfStock(){
		int minNo = totalOfBrooms;
		
		if (totalOfHeads < minNo)
			minNo = totalOfHeads;
		if (totalOfTorsos < minNo)
			minNo = totalOfTorsos;
		if ((totalOfHands/2) < minNo)
			minNo = (totalOfHands/2);
		if ((totalOfLegs/2) < minNo)
			minNo = (totalOfLegs/2);
		
		noOfLeastStockedPart = minNo;
	}
	
	private void assembleSCrow() {
		int randomNum;
		randomNum = PRODUCTION_TIME_MIN + (int)(Math.random() * ((PRODUCTION_TIME_MAX - PRODUCTION_TIME_MIN) + 1));

		try {
			sleep(randomNum);
			totalOfBrooms--;
			totalOfHeads--;
			totalOfTorsos--;
			totalOfHands-=2;
			totalOfLegs-=2;

			sCrowCount++;
			msg("SCAREROW # " + sCrowCount + " ASSEMBLED");
		} catch (InterruptedException e) {
		}
	}
}

